package com.fs.base.utils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;

/**
 * 反射相关工具类
 * <p>Created by Raofeicheng on 2016-10-22.</p>
 * @author Raofeicheng
 * @version 1.0
 */
public class ReflectionUtils extends org.springframework.util.ReflectionUtils {

	public static <T> Class<T> getGenericityType(Class<?> clazz, int index) {
		Type genType = clazz.getGenericSuperclass();
		if (!(genType instanceof ParameterizedType)) {
			return null;
		}
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		if (index < params.length) return (Class<T>) params[index];
		return null;
	}

	public static <T> T getFieldValue(Object obj, String fieldName) {
		if (null == obj || StringUtils.isBlank(fieldName)) return null;
		String[] paths = fieldName.split("[.]");
		if (1 < paths.length) {
			Object val = obj;
			for (String p : paths) {
				val = getFieldValue(val, p);
			}
			return (T) val;
		} else {
			if (obj instanceof Map) {
				return (T) ((Map) obj).get(fieldName);
			}
			Field field = null;
			PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(obj.getClass(), fieldName);
			if (null != pd && null != pd.getReadMethod()) {
				makeAccessible(pd.getReadMethod());
				return (T) invokeMethod(pd.getReadMethod(), obj);
			} else if (null != (field = findField(obj.getClass(), fieldName))) {
				try {
					makeAccessible(field);
					return (T) field.get(obj);
				} catch (IllegalAccessException e) {
					logger.error("不可能抛出的异常", e);
				}
			}
			throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
		}
	}

	public static void setFieldValue(Object obj, String fieldName, Object value) {
		if (null == obj || StringUtils.isBlank(fieldName)) return;
		Field field = findField(obj.getClass(), fieldName);
		if (null == field) {
			PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(obj.getClass(), fieldName);
			if (null != pd.getWriteMethod()) {
				makeAccessible(pd.getWriteMethod());
				invokeMethod(pd.getWriteMethod(), obj, value);
			}
		} else {
			try {
				makeAccessible(field);
				field.set(obj, value);
				return;
			} catch (IllegalAccessException e) {
				logger.error("不可能抛出的异常", e);
			}
		}
		throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
	}

	private static Logger logger = Logger.getLogger(ReflectionUtils.class);

	private ReflectionUtils() {

	}

}
